package com.win.oauth.service.impl;

import com.fyl.core.advance.constant.IResponseEnum;
import com.fyl.core.advance.constant.enums.CommonResponseEnum;
import com.fyl.security.service.OAuthService;
import com.win.oauth.entity.Permission;
import com.win.oauth.entity.RolePermissionRel;
import com.win.oauth.entity.UserRoleRel;
import com.win.oauth.service.IPermissionService;
import com.win.oauth.service.IRolePermissionRelService;
import com.win.oauth.service.IUserRoleRelService;
import com.win.oauth.utils.JWTUtils;
import com.win.oauth.utils.PathUtil;
import com.win.oauth.utils.UserClaims;
import com.win.oauth.utils.UserClaimsHolder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

public class OAuthServiceImpl implements OAuthService {

    @Autowired
    IPermissionService permissionService;

    @Autowired
    IRolePermissionRelService rolePermissionRelService;

    @Value("${oauth.need-check-path}")
    private List<String> needCheckPath;

    @Override
    public IResponseEnum doCheckHandler(HttpServletRequest request) {
        String requestPath = request.getRequestURI();
        String accessToken = request.getHeader("accessToken");
        if (StringUtils.isBlank(accessToken)) {
            return CommonResponseEnum.UNAUTHORIZED;
        }
        UserClaims userClaims = JWTUtils.verity(accessToken);
        // todo 根据签发时间 制作黑名单
        if (null == userClaims) {
            return CommonResponseEnum.UNAUTHORIZED;
        }

        if (!userClaims.isAdmin()) {
            // matched permission ids
            List<Long> permissionIds = permissionService.list().stream()
                    .filter(el -> PathUtil.match(el.getUrl(), requestPath))
                    .map(Permission::getId)
                    .collect(toList());

            if (!permissionIds.isEmpty()) {
                List<Long> roleIds = userClaims.getRoleIds();
                List<RolePermissionRel> rolePermRels = rolePermissionRelService.lambdaQuery()
                        .in(RolePermissionRel::getRoleId, roleIds).list();
                Set<Long> hasPermIdSet = rolePermRels.stream().map(RolePermissionRel::getPermissionId).collect(toSet());
                boolean matchFlag = permissionIds.stream().anyMatch(hasPermIdSet::contains);
                if (!matchFlag) {
                    return CommonResponseEnum.FORBIDDEN;
                }
            }
        }

        UserClaimsHolder.set(userClaims);
        return CommonResponseEnum.SUCCESS;
    }

    @Override
    public boolean preCheckHandler(HttpServletRequest request) {
        String requestPath = request.getRequestURI();
        for (String pattenPath : needCheckPath) {
            if (PathUtil.match(pattenPath, requestPath)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void postCheckHandler(HttpServletResponse response) {
        UserClaimsHolder.clear();
    }
}
